#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/queue.h>
#include "common.h"
#include <search.h>

struct TVTS_TAILQ_ENTRY {
	char* data;
	TAILQ_ENTRY(TVTS_TAILQ_ENTRY) entries;
};

TAILQ_HEAD(TVTS_TAILQ_HEAD, TVTS_TAILQ_ENTRY);

int upset(struct hsearch_data *phtab, char *key, char *val, struct TVTS_TAILQ_HEAD *plist_head) {
	ENTRY item, *entry;
	item.key = cp_str(key);
	if (!hsearch_r(item, FIND, &entry, phtab)) {
		item.data = (void*)cp_str(val);
		if (!hsearch_r(item, ENTER, &entry, phtab)) {
			fprintf(stderr, "Cannot insert %s => %s!\n", item.key, (char*)item.data);
			return 0;
		} else {
			printf("Inserted %s => %s.\n", item.key, (char*)item.data);
			if (plist_head) {
				struct TVTS_TAILQ_ENTRY *np = malloc(sizeof(struct TVTS_TAILQ_ENTRY));
				np->data = cp_str(key);
				TAILQ_INSERT_TAIL(plist_head, np, entries);
				printf("Inserted %s into list tail.\n", item.key);
			}
		}
	} else {
		printf("Updating %s from %s to %s.\n", item.key, (char*)entry->data, val);
		free(entry->data);
		entry->data = (void*)cp_str(val);
	}
	return 1;
}

int main(int argc, char* argv[]) {
	char buf[MAXLINE], buf2[MAXLINE];

	// SLL
	struct TVTS_TAILQ_ENTRY *np = 0, *n1 = 0, *n2 = 0;
	struct TVTS_TAILQ_HEAD head;
	TAILQ_INIT(&head);

	// init
	struct hsearch_data htab = {0}, htab2 = {0};
	if(!hcreate_r(100, &htab)) {
		fprintf(stderr, "%s\n", "Cannot create the hashtable!");
	} else {
		printf("%s\n", "Hashtable created.");
	}
	if(!hcreate_r(100, &htab2)) {
			fprintf(stderr, "%s\n", "Cannot create the hashtable2!");
		} else {
			printf("%s\n", "Hashtable2 created.");
		}

	// check and insert
	printf("Inserting ...\n");
	int i, first = 1;
	for (i = 1; i < argc; i ++) {
		char* arg = argv[i];
		snprintf(buf, MAXLINE, "%s-%d-%s", arg, i, arg);
		substr(buf, buf2, 0, 4);

		upset(&htab, arg, buf, &head);
		upset(&htab2, arg, buf2, 0);
	}
	printf("Insertions done.\n");

	// iterate
	printf("Start iteration ...\n");
	i = 0;
	TAILQ_FOREACH(np, &head, entries) {
    	printf("%d: %s\n", ++i, np->data);
    	ENTRY the_entry;
    	the_entry.key = np->data;
		ENTRY *entry = 0, *entry2 = 0;
    	if (!hsearch_r(the_entry, FIND, &entry, &htab)) {
    		fprintf(stderr, "Cannot found %s in htab!\n", the_entry.key);
    	} else if (!hsearch_r(the_entry, FIND, &entry2, &htab2)) {
    		fprintf(stderr, "Cannot found %s in htab2!\n",  the_entry.key);
    	} else {
    		printf("%s => %s (%s)\n", np->data, (char*)entry->data, (char*)entry2->data);
    	}
	}
	printf("Iteration done.\n");

	// destruct
	printf("Cleaning htab and htab2 ...\n");
	i = 0;
	TAILQ_FOREACH(np, &head, entries) {
		printf("%d: %s\n", ++i, np->data);
		ENTRY the_entry;
		the_entry.key = np->data;
		ENTRY *entry = 0, *entry2 = 0;
		if (!hsearch_r(the_entry, FIND, &entry, &htab)) {
			fprintf(stderr, "Cannot found %s in htab!\n", the_entry.key);
		} else if (!hsearch_r(the_entry, FIND, &entry2, &htab2)) {
			fprintf(stderr, "Cannot found %s in htab2!\n",  the_entry.key);
		} else {
			free(entry->key);
			free(entry->data);
			free(entry2->key);
			free(entry2->data);
		}
	}
	hdestroy_r(&htab);
	hdestroy_r(&htab2);
	printf("Cleaning htab and htab2 done.\n");

	printf("Cleaning tail queue ...\n");
	n1 = TAILQ_FIRST(&head);
	while (n1 != NULL) {
		printf("Cleaning %s\n", (char*)n1->data);
		n2 = TAILQ_NEXT(n1, entries);
		free(n1->data);
		free(n1);
		n1 = n2;
	}
    TAILQ_INIT(&head);
    printf("Cleaning tail queue done.\n");
    printf("Cleaning done.\n");
}
